/*
 *
 */
package jackal;

import java.awt.Color;
import java.awt.Point;
import java.util.*;
import javax.swing.*;

/**
 * Вспомогательный класс для хранения и быстрой выдачи всех объектов мира
 * 
 * @author pisklenov
 */
class World {
	Island island;
	Gamer gamer1;
	Gamer gamer2;
	private static ArrayList<Money> money = new ArrayList();

	World(Island island, Gamer gamer1, Gamer gamer2) {
		this.island = island;
		this.gamer1 = gamer1;
		this.gamer2 = gamer2;
	}

	public Gamer getEnemyGamerFor(Gamer gamer) {
		if (gamer.equals(gamer1)) {
			return gamer2;
		}
		return gamer1;
	}

	public ArrayList<Gamer.Boat> getBoats() {
		ArrayList<Gamer.Boat> boats = new ArrayList();

		boats.add(gamer1.boat);
		boats.add(gamer2.boat);

		return boats;
	}

	public ArrayList<Gamer.Pirate> getPirates() {
		ArrayList<Gamer.Pirate> pirates = new ArrayList();

		pirates.add(gamer1.pirate1);
		pirates.add(gamer1.pirate2);

		pirates.add(gamer2.pirate1);
		pirates.add(gamer2.pirate2);

		return pirates;
	}

	public ArrayList<Chest> getChests() {
		ArrayList<Chest> chests = new ArrayList();
		for (int i = 0; i < Island.BOARD_SIZE; i++) {
			for (int j = 0; j < Island.BOARD_SIZE; j++) {
				if (island.getPlace(i, j).getType() == BasicObj.SPEC_CHEST) {
					chests.add((Chest) island.getPlace(i, j));
				}
			}
		}
		return chests;
	}

	public boolean isGameOver() {
		if (this.moneyInWorld() == 0) {
			return true;
		}
		return false;
	}

	public int moneyInWorld() {
		List<Chest> chests = getChests();
		int moneyCount = 0;

		for (int i = 0; i < chests.size(); i++) {
			moneyCount += chests.get(i).getGoldCount();
		}

		return moneyCount;
	}

	public ArrayList<Money> getMoney() {
		return World.money;
	}

	public static void addMoney(Point point) {
		Money newMoney = new Money();
		newMoney.setCoord(point);
		money.add(newMoney);
	}

	public static void delMoney(Point point) {
		for (int i = 0; i < money.size(); i++) {
			if (point.equals(money.get(i).getCoord())) {
				money.get(i).showedState = Money.STATE_MUST_REMOVED;
				break;
			}
		}
	}
}

/**
 * <p>
 * Класс монеты,
 * </p>
 * появляется если пират бросает монету является подклассом {@link #JLabel
 * JLabel} реализует {@link #BasicObj BasicObj}
 * 
 * @author pisklenov
 */
class Money extends JLabel implements BasicObj {
	private Point coord = new Point();
	private int type = BasicObj.SPEC_MONEY;
	public int showedState = STATE_CREATED; // начально сосотояние

	public static final int STATE_CREATED = 0;
	public static final int STATE_VISIBLE = 1; // монета видима на игровом поле
	public static final int STATE_MUST_REMOVED = 2; // монету подобрали и она
													// будет удалена

	public final int offset = 20;

	javax.swing.ImageIcon icon; // рисунок монеты

	Money() {
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\money.gif");

		this.setIcon(this.icon);
		this.setSize(this.icon.getIconWidth(), this.icon.getIconHeight());

		this.setToolTipText("Да это же золото!!!");
	}

	@Override
	public int getType() {
		return type;
	}

	@Override
	public Point getCoord() {
		return coord;
	}

	public void setCoord(Point coord) {
		this.coord = coord;
	}
}

/**
 * <p>
 * Класс стрелки,
 * </p>
 * перекидывает наступившего пирата в указанном направлении<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Arrow extends Place implements BasicObj {
	private int direction; // направление, в которое переместится пират 0 -
							// север, 1 - восток, 2 - юг, 3 - запад

	Arrow() {
		type = BasicObj.SPEC_ARROW;
		this.setToolTipText("Не исследовано");
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background.jpg");

		direction = (int) Math.floor(Math.random() * 4);
		switch (direction) {
		case 0:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\arrow_north.png");
			break;
		case 1:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\arrow_east.png");
			break;
		case 2:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\arrow_south.png");
			break;
		case 3:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\arrow_west.png");
			break;

		default:
			break;
		}
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Это стрелка, иди в клетку, куда она указывает");

			if (isLog) {
				System.out.println(pirate.getName() + " наступил на стрелку "
						+ this.direction);
			}
		}

		switch (direction) {
		case 0:
			pirate.moveTo(new Point(pirate.getCoord().x, pirate.getCoord().y - 1), world);
			break;
		case 1:
			pirate.moveTo(new Point(pirate.getCoord().x + 1,
					pirate.getCoord().y), world);
			break;
		case 2:
			pirate.moveTo(new Point(pirate.getCoord().x, pirate.getCoord().y + 1), world);
			break;
		case 3:
			pirate.moveTo(new Point(pirate.getCoord().x - 1,
					pirate.getCoord().y), world);
			break;

		default:
			break;
		}
	}
}

/**
 * <p>
 * Класс болота,
 * </p>
 * не дает пирату сдвинуться с места указазное количество ходов<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class SlowDown extends Place implements BasicObj {
	private int slowCount; // количество замедлений

	SlowDown() {
		type = BasicObj.SPEC_SLOWDOWN;
		this.setToolTipText("Не исследовано");
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background.jpg");
		iconReversed = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\swamp.png");

		slowCount = (int) Math.floor(Math.random() * 3) + 1;
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Это трясина, ты проседишь тут " + slowCount
					+ " хода");

			if (isLog) {
				System.out.println(pirate.getName()
						+ " наступил на трясину и пробудет здесь " + slowCount
						+ " хода");
			}
		}

		if (pirate.alive) {
			for (int i = 0; i < this.slowCount; i++) {
				pirate.way.add(0, getCoord());
			}
			pirate.alive = false;
		} else {
			if (pirate.way.size() == 1)
				;
		}
	}
}

/**
 * <p>
 * Класс сундука с монетами,
 * </p>
 * каждый сундук содержит указанное количество монет<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Chest extends Place implements BasicObj {
	private int goldCount = 3;

	javax.swing.ImageIcon emptyChestIcon;

	Chest() {
		type = BasicObj.SPEC_CHEST;
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background.jpg");
		iconReversed = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\chest.png");
		emptyChestIcon = new javax.swing.ImageIcon(
				System.getProperty("user.dir") + "\\img\\chest_empty.png");

		this.setToolTipText("Не исследовано");
	}

	public int getGoldCount() {
		return goldCount;
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Да это же сундук полный золота!");

			if (isLog) {
				System.out.println(pirate.getName() + " нашел сундук");
			}
		}

		if (goldCount > 0 && !pirate.haveMoney) {
			pirate.addMoney();
			goldCount--;

			if (isLog) {
				System.out.println(pirate.getName() + " взял монету");
			}
		}

		if (goldCount <= 0) {
			this.setIcon(emptyChestIcon);
			this.setToolTipText("Сундук пуст");

			if (isLog) {
				System.out.println("Сундук пуст");
			}
		}
	}
}

/**
 * <p>
 * Класс джунглей
 * </p>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Jungle extends Place implements BasicObj {
	Jungle() {
		type = BasicObj.JUNGLE;
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background.jpg");
		iconReversed = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background_reversed.jpg");
		this.setToolTipText("Не исследовано");
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Ничего интересного, просто джунгли");

			if (isLog) {
				System.out.println("Переворачиваем картучку джунглей");
			}
		}
	}
}

/**
 * Класс пушки. Пирата, наступившего на пушку
 * выстреливает в море в указанном направлении<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Cannon extends Place implements BasicObj {
	private int direction; // направление, в которое переместится пират 0 -
							// север, 1 - восток, 2 - юг, 3 - запад

	Cannon() {
		type = BasicObj.SPEC_CANNON;
		this.setToolTipText("Не исследовано");

		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background_reversed.jpg");

		direction = (int) Math.floor(Math.random() * 4);
		switch (direction) {
		case 0:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\cannon0.png");
			break;
		case 1:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\cannon1.png");
			break;
		case 2:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\cannon2.png");
			break;
		case 3:
			iconReversed = new javax.swing.ImageIcon(
					System.getProperty("user.dir") + "\\img\\cannon3.png");
			break;

		default:
			break;
		}
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Это пушка, она запустит тебя в воду");

			if (isLog) {
				System.out.println(pirate.getName() + " наступил на пушку "
						+ this.direction);
			}
		}

		switch (direction) {
		case 0:
			pirate.setCoord(new Point(pirate.getCoord().x, 1));
			pirate.moveTo(new Point(pirate.getCoord().x, 0), world);
			break;
		case 1:
			pirate.setCoord(new Point(Island.BOARD_SIZE - 2,
					pirate.getCoord().y));
			pirate.moveTo(
					new Point(Island.BOARD_SIZE - 1, pirate.getCoord().y),
					world);
			break;
		case 2:
			pirate.setCoord(new Point(pirate.getCoord().x,
					Island.BOARD_SIZE - 2));
			pirate.moveTo(
					new Point(pirate.getCoord().x, Island.BOARD_SIZE - 1),
					world);
			break;
		case 3:
			pirate.setCoord(new Point(1, pirate.getCoord().y));
			pirate.moveTo(new Point(0, pirate.getCoord().y), world);
			break;

		default:
			break;
		}
	}

}


/**
 * Класс самолета. Быстро перемещает пирата на его корабль
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Aircraft extends Place implements BasicObj {
	Aircraft() {
		type = BasicObj.SPEC_AIRCRAFT;
		this.setToolTipText("Не исследовано");

		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\jungle_background_reversed.jpg");
		iconReversed = new javax.swing.ImageIcon(System.getProperty("user.dir") 
				+ "\\img\\aircraft.png");
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Это самолет, с его помощью можно бытсро отпарвиться к " +
					"себе на корабль");
		}
		
		if (isLog) {
			System.out.println(pirate.getName() + " садится в самолет и отправляется к" +
					" себе на корабль");
		}
		
		if (pirate.gamer().boat.getCoord().y == 0) {
			pirate.setCoord(new Point(pirate.gamer().boat.getCoord().x, 1));
			
			pirate.moveTo(pirate.gamer().boat.getCoord(), world);
		} else if (pirate.gamer().boat.getCoord().y == Island.BOARD_SIZE-1) {
			pirate.setCoord(new Point(pirate.gamer().boat.getCoord().x, Island.BOARD_SIZE-2));
			
			pirate.moveTo(pirate.gamer().boat.getCoord(), world);
		} else {
			System.out.println("[Ошибка] Что-то странное с кораблем, не реальные координаты");
		}
	}
}

/**
 * Класс замка. пирата, находящегося в замке нельзя ударить<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Castle extends Place implements BasicObj {
	Castle() {
		type = BasicObj.SPEC_CASTLE;
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\castle.png");//jungle_background.jpg");
		iconReversed = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\castle.png");
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (!reversed) {
			reversed = true;
			this.setIcon(iconReversed);
			this.setToolTipText("Это крепость, в ней ты в безопасности");

			if (isLog) {
				System.out.println(pirate.getName() + " зашел в крепость");
			}
		}
		
		pirate.setImmortal(true);
	}
}

/**
 * Класс воды, если пират прыгает в воду с монетой - он ее теряет<br>
 * является подклассом {@link #Place Place} реализует {@link #BasicObj BasicObj}
 */
class Water extends Place implements BasicObj {
	Water() {
		type = BasicObj.WATER;
		icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
				+ "\\img\\water_background.jpg");
	}

	@Override
	public void doSomthing(Gamer.Pirate pirate, World world) {
		if (pirate.haveMoney) {
			pirate.delMoney();

			if (isLog) {
				System.out.println("Пират падает в воду и теряет монету");
			}
		}

	}
}

/**
 * Суперкласс для всех типов местностей<br>
 * является подклассом {@link #JLabel JLabel} реализует {@link #BasicObj
 * BasicObj}
 */
class Place extends JLabel implements BasicObj {
	public final static int CELL_SIZE = 50;
	public boolean reversed = false; // все клетки в начале игры не перевернуты

	private Point coord; // координаты места [0..BOARD_SIZE-1, 0..BOARD_SIZE-1]
	public int type;

	javax.swing.ImageIcon icon; // у каждой клетки должен быть рисунок
	javax.swing.ImageIcon iconReversed; // обратный рисунок

	public void setCoord(Point point) {
		this.coord = point;
	}

	public void doSomthing(Gamer.Pirate pirate, World world) {
	}

	@Override
	public int getType() {
		return type;
	}

	@Override
	public Point getCoord() {
		return this.coord;
	}
}

class Island {
	public final static int BOARD_SIZE = 13; // размер поля 13х13
	private Place[][] places = new Place[BOARD_SIZE][BOARD_SIZE];

	public Place getPlace(int i, int j) {
		return places[i][j];
	}

	public static int getDistanceFromTo(Point from, Point to) {
		double result;
		result = Math.sqrt(Math.pow(from.x - to.x, 2)
				+ Math.pow(from.y - to.y, 2));
		return (int) Math.round(result);
	}

	private void prepareLabel(JLabel label) {
		label.setVerticalAlignment(JLabel.TOP);
		label.setHorizontalAlignment(JLabel.CENTER);
		label.setOpaque(true);
		label.setForeground(Color.black);
		label.setSize(Place.CELL_SIZE, Place.CELL_SIZE);
	}

	private Castle createCastle(Point coord) {
		Castle castle = new Castle();

		prepareLabel(castle);

		castle.setIcon(castle.icon);
		castle.setCoord(coord);

		return castle;
	}
	
	private SlowDown createSlowDown(Point coord) {
		SlowDown slowDown = new SlowDown();

		prepareLabel(slowDown);

		slowDown.setIcon(slowDown.icon);
		slowDown.setCoord(coord);

		return slowDown;
	}

	private Arrow createArrow(Point coord) {
		Arrow arrow = new Arrow();

		prepareLabel(arrow);

		arrow.setCoord(coord);
		arrow.setIcon(arrow.icon);

		return arrow;
	}

	private Chest createChest(Point coord) {
		Chest chest = new Chest();

		prepareLabel(chest);

		chest.setCoord(coord);
		chest.setIcon(chest.icon);

		return chest;
	}

	private Cannon createCannon(Point coord) {
		Cannon cannon = new Cannon();

		prepareLabel(cannon);

		cannon.setCoord(coord);
		cannon.setIcon(cannon.icon);

		return cannon;
	}
	
	private Aircraft createAircraft(Point coord) {
		Aircraft aircraft = new Aircraft();

		prepareLabel(aircraft);

		aircraft.setCoord(coord);
		aircraft.setIcon(aircraft.icon);

		return aircraft;
	}

	private Water createWater(Point coord) {
		Water water = new Water();

		prepareLabel(water);

		water.setCoord(coord);
		water.setIcon(water.icon);

		return water;
	}

	private Jungle createJungle(Point coord) {
		Jungle jungle = new Jungle();

		prepareLabel(jungle);

		jungle.setCoord(coord);
		jungle.setIcon(jungle.icon);

		return jungle;
	}

	public Island() {
		this.Init();
	}

	private void Init() {
		for (int i = 0; i < BOARD_SIZE; i++) {
			for (int j = 0; j < BOARD_SIZE; j++) {
				places[i][j] = new Place();
				places[i][j] = createJungle(new Point(i, j));
			}
		}

		for (int i = 0; i < BOARD_SIZE; i++) {
			places[i][0] = createWater(new Point(i, 0));
		}

		for (int i = 0; i < BOARD_SIZE; i++) {
			places[i][BOARD_SIZE - 1] = createWater(new Point(i, BOARD_SIZE - 1));
		}

		for (int j = 0; j < BOARD_SIZE; j++) {
			places[0][j] = createWater(new Point(0, j));
		}

		for (int j = 0; j < BOARD_SIZE; j++) {
			places[BOARD_SIZE - 1][j] = createWater(new Point(BOARD_SIZE - 1, j));
		}

		places[1][1] = createWater(new Point(1, 1));
		places[BOARD_SIZE - 2][1] = createWater(new Point(BOARD_SIZE - 2, 1));
		places[BOARD_SIZE - 2][BOARD_SIZE - 2] = createWater(new Point(
				BOARD_SIZE - 2, BOARD_SIZE - 2));
		places[1][BOARD_SIZE - 2] = createWater(new Point(1, BOARD_SIZE - 2));

		ArrayList<Point> allPlacesList = this.getAllPlaces();
		//System.out.println(allPlacesList.size());
		
		generateObject(allPlacesList, BasicObj.SPEC_CHEST, 5); // генерируем сундуки
		generateObject(allPlacesList, BasicObj.SPEC_ARROW, 3); // генерируем стрелки
		generateObject(allPlacesList, BasicObj.SPEC_SLOWDOWN, 2); // генерируем болота
		generateObject(allPlacesList, BasicObj.SPEC_CANNON, 1); // генерируем пушки
		generateObject(allPlacesList, BasicObj.SPEC_CASTLE, 2); // генерируем крепости
		generateObject(allPlacesList, BasicObj.SPEC_AIRCRAFT, 2); // генерируем самолеты
	}
	
	private void generateObject(ArrayList<Point> placesList, int type, int count) {
		for (int i = 0; i < count; i++) { // генерируем объекты
			int n = (int) Math.floor(Math.random() * placesList.size());

			switch (type) {
				case BasicObj.SPEC_ARROW:
					places[placesList.get(n).x][placesList.get(n).y] = createArrow(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				case BasicObj.SPEC_CASTLE:
					places[placesList.get(n).x][placesList.get(n).y] = createCastle(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				case BasicObj.SPEC_CHEST:
					places[placesList.get(n).x][placesList.get(n).y] = createChest(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				case BasicObj.SPEC_CANNON:
					places[placesList.get(n).x][placesList.get(n).y] = createCannon(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				case BasicObj.SPEC_SLOWDOWN:
					places[placesList.get(n).x][placesList.get(n).y] = createSlowDown(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				case BasicObj.SPEC_AIRCRAFT:
					places[placesList.get(n).x][placesList.get(n).y] = createAircraft(new Point(
							placesList.get(n).x, placesList.get(n).y));
					break;
				default: 
					System.out.println("[Ошибка] Нет такого типа объектов");
					break;
			}

			placesList.remove(n);
		}
	}

	public ArrayList<Point> getAllPlaces() {
		ArrayList<Point> list = new ArrayList<Point>();

		for (int i = 0; i < BOARD_SIZE; i++) {
			for (int j = 0; j < BOARD_SIZE; j++) {
				System.out.println(i + " " + j);
				if (places[i][j].getType() == BasicObj.JUNGLE) {
					list.add(new Point(i, j));
					System.out.println(i + " " + j);
				}
			}
		}
		return list;
	}
}

class Gamer {
	class Boat extends JLabel implements BasicObj {
		private Point coord = new Point();
		public int type = BasicObj.BOAT;
		public ImageIcon icon;

		int moneyCount = 0; // в начале у каждого игрока нет монет на корабле

		Boat() {
			icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
					+ "\\img\\viking-ship-icon.png");
		}

		public Gamer gamer() {
			return Gamer.this;
		}

		public void addMoney() {
			moneyCount++;
		}

		private int getDistanceTo(Point toPoint) {
			double result;

			result = Math.sqrt(Math.pow(coord.x - toPoint.x, 2)
					+ Math.pow(coord.y - toPoint.y, 2));

			return (int) Math.round(result);
		}

		public boolean canMoveTo(Place place) {
			if (getDistanceTo(place.getCoord()) != 1) {
				return false;
			}
			if (place.getType() != BasicObj.WATER) {
				return false;
			}
			return true;
		}

		public boolean moveTo(Point point, World world) {
			if (!this.canMoveTo(world.island.getPlace(point.x, point.y))) {
				if (isLog) {
					System.out.println(this.getName() + " не может туда пойти "
							+ point);
				}
				return false;
			}

			ArrayList<Gamer.Pirate> pirates = world.getPirates(); // ищем
																	// столкновения
																	// с другими
																	// пиратами
			for (int i = 0; i < pirates.size(); i++) {
				if (pirates.get(i).getDistanceTo(this.getCoord()) == 0
						&& pirates.get(i).gamer().team == this.gamer().team) {
					pirates.get(i).setCoord(point);
				}
			}

			this.coord = point;

			if (isLog) {
				System.out.println("Корабль плывет в клетку " + point);
			}

			return true;
		}

		@Override
		public int getType() {
			return type;
		}

		@Override
		public Point getCoord() {
			return coord;
		}
	}

	class Pirate extends JLabel implements BasicObj {
		private final int type = BasicObj.PIRATE;
		private Point coord = new Point();
		private String name = "";
		private boolean immortal = false;
		
		public ArrayList<Point> way = new ArrayList<Point>();
		public boolean haveMoney = false; // без денег
		public boolean alive = true;
		public int offsetX = 0;
		
		ImageIcon icon;
		ImageIcon iconWithMoney;

		public Gamer gamer() {
			return Gamer.this;
		}

		Pirate(int team) {
			if (team == 1) {
				icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
						+ "\\img\\pirate1.gif");
				setName("Ваш пират");
			}
			if (team == 2) {
				icon = new javax.swing.ImageIcon(System.getProperty("user.dir")
						+ "\\img\\pirate2.gif");
				setName("Вражеский пират");
			}

			this.setToolTipText(this.getName());
		}

		@Override
		public final void setName(String name) {
			this.name = name;
		}

		@Override
		public final String getName() {
			return this.name;
		}

		public void dropMoney() {
			if (this.haveMoney) {
				this.delMoney();
				World.addMoney(this.getCoord());
			}
		}

		public int getDistanceTo(Point toPoint) {
			double result;
			result = Math.sqrt(Math.pow(coord.x - toPoint.x, 2)
					+ Math.pow(coord.y - toPoint.y, 2));
			return (int) Math.round(result);
		}

		public boolean canMoveTo(Point toPoint) {
			if (getDistanceTo(toPoint) > 1) {
				return false;
			}
			return true;
		}

		public boolean canMoveTo(Place place) {
			if (getDistanceTo(place.getCoord()) > 1) {
				return false;
			}
			if (haveMoney && !place.reversed) {
				return false;
			}

			return true;
		}

		public boolean goNextWayPoint(World world) {
			if (!this.way.isEmpty()) {
				this.moveTo(this.way.get(0), world);
				this.way.remove(0);
				return true;
			} else {
				return false;
			}
		}

		public boolean moveTo(Point point, World world) {
			if (isLog) {
				// System.out.println("+++"+this.getName());
			}

			Place place = world.island.getPlace(point.x, point.y);

			if (!this.canMoveTo(point)) {
				if (isLog) {
					System.out.println(this.getName() + " не может туда пойти "
							+ point);
				}
				return false;
			}

			List<Gamer.Boat> boats = world.getBoats(); // ищем столкновения с
														// чужими кораблями
			for (int i = 0; i < boats.size(); i++) {
				if (boats.get(i).getDistanceTo(point) == 0
						&& boats.get(i).gamer().team != this.gamer().team) {

					this.gotHit();
					if (isLog) {
						System.out.println(this.getName()
								+ " получает удар от лодки");
					}

					return true;
				}
			}

			if (place.getCoord().equals(this.gamer().boat.coord)
					&& this.haveMoney) {
				this.gamer().boat.addMoney();
				this.delMoney();
				if (isLog) {
					System.out.println(this.getName()
							+ " принес монету на корабль");
				}
			}

			// ищем столкновения с другими пиратами
			ArrayList<Gamer.Pirate> pirates = world.getPirates();
			for (int i = 0; i < pirates.size(); i++) {
				if (pirates.get(i).getDistanceTo(point) == 0 // если в точку, куда наступаем стоит пират
						&& this.hashCode() != pirates.get(i).hashCode() // и это не я
						&& pirates.get(i).gamer().team != this.gamer().team) {  // и это вражеский пират
	
					if (pirates.get(i).isImmortal()) { // если пират в крепости
						if (isLog) {
							System.out.println("Нельзя ударить " + pirates.get(i).getName()+
									", так как он в крепости");
						}
						
						return false; // выходим и не засчитываем ход
					}
					
					if (isLog) {
						System.out.println(this.getName() + " бьет "
								+ pirates.get(i).getName());
					}
					if (pirates.get(i).haveMoney) {
						this.addMoney();
						pirates.get(i).delMoney();
					}

					pirates.get(i).gotHit();
				}
			}

			if (place.getType() == BasicObj.JUNGLE) {
				if (this.haveMoney && !place.reversed) {
					if (isLog) {
						System.out.println(this.getName()
								+ " нельзя ходить по джунглям с деньгами");
					}
					return false;
				}
			}

			// если наступил на монету
			for (int i = 0; i < world.getMoney().size(); i++) {
				Money money = world.getMoney().get(i);
				if (money.getCoord().equals(place.getCoord())
						&& money.showedState != Money.STATE_MUST_REMOVED
						&& !this.haveMoney) {
					this.addMoney();
					World.delMoney(place.getCoord());

					if (isLog) {
						System.out.println(this.getName() + " подобрал золото");
					}
				}
			}

			this.setImmortal(false);

			this.coord = place.getCoord();
			place.doSomthing(this, world);

			if (isLog) {
				System.out.println(this.getName() + " ходит в клетку "
						+ place.getCoord());
			}

			return true;
		}

		private void gotHit() {
			this.delMoney();
			this.way.clear();
			this.coord = this.gamer().boat.getCoord();
		}

		public void addMoney() {
			if (!this.haveMoney) {
				haveMoney = true;

				if (team == 1) {
					iconWithMoney = new javax.swing.ImageIcon(
							System.getProperty("user.dir")
									+ "\\img\\pirate_with_money1.gif");
				}
				if (team == 2) {
					iconWithMoney = new javax.swing.ImageIcon(
							System.getProperty("user.dir")
									+ "\\img\\pirate_with_money2.gif");
				}
				this.setIcon(iconWithMoney);
			}
		}

		public void delMoney() {
			if (this.haveMoney) {
				this.haveMoney = false;
				this.setIcon(icon);
			}
		}

		@Override
		public int getType() {
			return type;
		}

		@Override
		public Point getCoord() {
			return coord;
		}

		public void setCoord(Point point) {
			this.coord = point;
		}

		public boolean isImmortal() {
			return immortal;
		}

		public void setImmortal(boolean immortal) {
			this.immortal = immortal;
		}
	}

	/*
	 * Переменные и константы для игрока
	 */
	public Boat boat;
	public Pirate pirate1, pirate2;
	public int team;

	// Create Boat
	private Boat createBoat() {
		Boat newBoat = new Boat();
		newBoat.setIcon(newBoat.icon);
		newBoat.setSize(newBoat.icon.getIconWidth(),
				newBoat.icon.getIconHeight());
		return newBoat;
	}

	private Pirate createPirate() {
		Pirate pirate = new Pirate(this.team);
		pirate.setIcon(pirate.icon);
		pirate.setSize(pirate.icon.getIconWidth(), pirate.icon.getIconHeight());
		return pirate;
	}

	Gamer(Point beginPos, int team) {
		this.team = team;

		this.boat = createBoat();

		this.boat.coord.x = beginPos.x;
		this.boat.coord.y = beginPos.y;

		this.pirate1 = createPirate();
		this.pirate2 = createPirate();
		// pirate2 = createPirate();
		// pirate3 = createPirate();

		this.pirate1.coord.x = this.boat.coord.x;
		this.pirate1.coord.y = this.boat.coord.y;

		this.pirate2.coord.x = this.boat.coord.x;
		this.pirate2.coord.y = this.boat.coord.y;

		this.pirate2.offsetX = 20;
		// pirate2.cord.posX = boat.cord.posX;
		// pirate2.cord.posX = boat.cord.posX;

		// pirate3.cord.posX = boat.cord.posX;
		// pirate3.cord.posX = boat.cord.posX;
	}
}

/**
 * Базовый интерфейс для всех объектов мира
 * 
 * @author pisklenovav
 */
interface BasicObj {
	public boolean isLog = true;

	public final static int NONE = -1;
	public final static int WATER = 0;

	public final static int JUNGLE = 2;
	public final static int BOAT = 10;
	public final static int PIRATE = 11;

	public final static int SPEC_CHEST = 16;
	public final static int SPEC_ARROW = 17;
	public final static int SPEC_MONEY = 20;

	public final static int SPEC_SLOWDOWN = 30;
	public final static int SPEC_CASTLE = 40;
	public final static int SPEC_CANNON = 50;
	
	public final static int SPEC_AIRCRAFT = 60;

	public int getType();
	public Point getCoord();
}

/**
 * 
 * @author dns
 */
public class JackalObjects {

	/**
	 * @param args
	 *            the command line arguments
	 * 
	 *            public static void main(String[] args) { // TODO code
	 *            application logic here }
	 */
}
